#include <stdio.h>
#include <stdlib.h>
#include "leptjson_v1.hpp"

static int main_ret = 0;
static int test_count = 0;
static int test_pass = 0;

#define EXPECT_EQ_BASE(equality, expect, actual, format)                      \
    do                                                                        \
    {                                                                         \
        test_count++;                                                         \
        if (equality)                                                         \
            test_pass++;                                                      \
        else                                                                  \
        {                                                                     \
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", \
                    __FILE__, __LINE__, expect, actual);                      \
            main_ret = 1;                                                     \
        }                                                                     \
    } while (0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")
#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%.17g")
#define EXPECT_EQ_STRING(expect, actual) EXPECT_EQ_BASE(actual.compare(expect) == 0, (std::string(expect)).c_str(), (std::string(actual)).c_str(), "%s")
#define EXPECT_EQ_SIZE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")
#define TEST_LITERAL(expect, json)                                               \
    do                                                                           \
    {                                                                            \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json);    \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type()); \
        EXPECT_EQ_INT(expect, v->lept_get_type());                               \
    } while (0)

#define TEST_NUMBER(expect, json)                                                \
    do                                                                           \
    {                                                                            \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json);    \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type()); \
        EXPECT_EQ_INT(lept_type::LEPT_NUMBER, v->lept_get_type());               \
        EXPECT_EQ_DOUBLE(expect, v->lept_get_element<double>());                 \
    } while (0)

#define TEST_STRING(expect, json)                                                \
    do                                                                           \
    {                                                                            \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json);    \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type()); \
        EXPECT_EQ_INT(lept_type::LEPT_STRING, v->lept_get_type());               \
        EXPECT_EQ_STRING(expect, v->lept_get_element<std::string>());            \
    } while (0)

#define TEST_ARRAY(expect, json)                                                                       \
    do                                                                                                 \
    {                                                                                                  \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json);                          \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type());                       \
        EXPECT_EQ_INT(lept_type::LEPT_ARRAY, v->lept_get_type());                                      \
        EXPECT_EQ_SIZE(expect, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>().size()); \
    } while (0)

#define TEST_ERROR(error, json)                                               \
    do                                                                        \
    {                                                                         \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json); \
        EXPECT_EQ_INT(error, v->lept_get_error_type());                       \
        EXPECT_EQ_INT(lept_type::LEPT_NULL, v->lept_get_type());              \
    } while (0)

/* LITERAL PARSE */

static void test_parse_null()
{
    TEST_LITERAL(lept_type::LEPT_NULL, "null");
}

static void test_parse_false()
{
    TEST_LITERAL(lept_type::LEPT_FALSE, "false");
}

static void test_parse_true()
{
    TEST_LITERAL(lept_type::LEPT_TRUE, "true");
}

/* NUMBER PARSE */

static void test_parse_number()
{
    TEST_NUMBER(0.0, "0");
    TEST_NUMBER(0.0, "-0");
    TEST_NUMBER(0.0, "-0.0");
    TEST_NUMBER(1.0, "1");
    TEST_NUMBER(-1.0, "-1");
    TEST_NUMBER(1.5, "1.5");
    TEST_NUMBER(-1.5, "-1.5");
    TEST_NUMBER(3.1416, "3.1416");
    TEST_NUMBER(1E10, "1E10");
    TEST_NUMBER(1e10, "1e10");
    TEST_NUMBER(1E+10, "1E+10");
    TEST_NUMBER(1E-10, "1E-10");
    TEST_NUMBER(-1E10, "-1E10");
    TEST_NUMBER(-1e10, "-1e10");
    TEST_NUMBER(-1E+10, "-1E+10");
    TEST_NUMBER(-1E-10, "-1E-10");
    TEST_NUMBER(1.234E+10, "1.234E+10");
    TEST_NUMBER(1.234E-10, "1.234E-10");
    TEST_NUMBER(0.0, "1e-10000"); /* must underflow */

    /* Boundary conditions for double*/
    TEST_NUMBER(1.0000000000000002, "1.0000000000000002");           /* the smallest number > 1 */
    TEST_NUMBER(4.9406564584124654e-324, "4.9406564584124654e-324"); /* minimum denormal */
    TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
    TEST_NUMBER(2.2250738585072009e-308, "2.2250738585072009e-308"); /* Max subnormal double */
    TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");
    TEST_NUMBER(2.2250738585072014e-308, "2.2250738585072014e-308"); /* Min normal positive double */
    TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
    TEST_NUMBER(1.7976931348623157e+308, "1.7976931348623157e+308"); /* Max double */
    TEST_NUMBER(-1.7976931348623157e+308, "-1.7976931348623157e+308");
}

/* STRING PARSE */

static void test_parse_string()
{
    TEST_STRING("", "\"\"");
    TEST_STRING("Hello", "\"Hello\"");
    TEST_STRING("Hello\nWorld", "\"Hello\\nWorld\"");
    TEST_STRING("\" \\ / \b \f \n \r \t", "\"\\\" \\\\ \\/ \\b \\f \\n \\r \\t\"");
#if 1
    TEST_STRING("\x24", "\"\\u0024\"");                    /* Dollar sign U+0024 */
    TEST_STRING("\xC2\xA2", "\"\\u00A2\"");                /* Cents sign U+00A2 */
    TEST_STRING("\xE2\x82\xAC", "\"\\u20AC\"");            /* Euro sign U+20AC */
    TEST_STRING("\xF0\x9D\x84\x9E", "\"\\uD834\\uDD1E\""); /* G clef sign U+1D11E */
    TEST_STRING("\xF0\x9D\x84\x9E", "\"\\ud834\\udd1e\""); /* G clef sign U+1D11E */
#endif
}

/* ARRAY PARSE */
#define TEST_ARRAY(expect, json)                                                                       \
    do                                                                                                 \
    {                                                                                                  \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json);                          \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type());                       \
        EXPECT_EQ_INT(lept_type::LEPT_ARRAY, v->lept_get_type());                                      \
        EXPECT_EQ_SIZE(expect, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>().size()); \
    } while (0)

static void test_parse_array()
{
    TEST_ARRAY(0, "[ ]");
#if 1
    std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse("[ null , false , true , 123 , \"abc\" ]");
    EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type());
    EXPECT_EQ_INT(lept_type::LEPT_ARRAY, v->lept_get_type());
    EXPECT_EQ_SIZE(5, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>().size());
    EXPECT_EQ_INT(lept_type::LEPT_NULL, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[0]->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_FALSE, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[1]->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_TRUE, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[2]->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_NUMBER, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[3]->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_STRING, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[4]->lept_get_type());
    EXPECT_EQ_DOUBLE(123, v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[3]->lept_get_element<double>());
    EXPECT_EQ_STRING("abc", v->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[4]->lept_get_element<std::string>());

    std::unique_ptr<ILeptJSON> v1 = MultiManageLeptJSON::lept_parse("[ [ ] , [ 0 ] , [ 0 , 1 ] , [ 0 , 1 , 2 ] ]");
    EXPECT_EQ_DOUBLE(0, v1->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[1]->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[0]->lept_get_element<double>());
#endif
}

typedef std::unordered_map<std::string, std::unique_ptr<ILeptJSON>> lept_umap_type;

static void test_parse_object()
{

    std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(" { } ");
    EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type());
    EXPECT_EQ_INT(lept_type::LEPT_OBJECT, v->lept_get_type());
    EXPECT_EQ_SIZE(0, v->lept_get_element<lept_umap_type>().size());

#if 1
    std::unique_ptr<ILeptJSON> v1 = MultiManageLeptJSON::lept_parse(
        " { "
        "\"n\" : null , "
        "\"f\" : false , "
        "\"t\" : true , "
        "\"i\" : 123 , "
        "\"s\" : \"abc\", "
        "\"a\" : [ 1, 2, 3 ],"
        "\"o\" : { \"1\" : 1, \"2\" : 2, \"3\" : 3 }"
        " } ");
    EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v1->lept_get_error_type());
    EXPECT_EQ_INT(lept_type::LEPT_OBJECT, v1->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_NULL, v1->lept_get_element<lept_umap_type>().at("n")->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_FALSE, v1->lept_get_element<lept_umap_type>().at("f")->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_TRUE, v1->lept_get_element<lept_umap_type>().at("t")->lept_get_type());
    EXPECT_EQ_INT(lept_type::LEPT_NUMBER, v1->lept_get_element<lept_umap_type>().at("i")->lept_get_type());
    EXPECT_EQ_INT(123, v1->lept_get_element<lept_umap_type>().at("i")->lept_get_element<double>());
    EXPECT_EQ_INT(lept_type::LEPT_STRING, v1->lept_get_element<lept_umap_type>().at("s")->lept_get_type());
    EXPECT_EQ_INT("abc", v1->lept_get_element<lept_umap_type>().at("s")->lept_get_element<std::string>());
    EXPECT_EQ_INT(lept_type::LEPT_ARRAY, v1->lept_get_element<lept_umap_type>().at("a")->lept_get_type());
    for (int i = 0; i < 3; i++)
    {
        double b = v1->lept_get_element<lept_umap_type>().at("a")->lept_get_element<std::vector<std::unique_ptr<ILeptJSON>>>()[i]->lept_get_element<double>();
        EXPECT_EQ_INT(i + 1, b);
    }
    EXPECT_EQ_INT(lept_type::LEPT_OBJECT, v1->lept_get_element<lept_umap_type>().at("o")->lept_get_type());

#endif
}

/* ERROR PARSE */
static void test_parse_expect_value()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_EXPECT_VALUE, "");
    TEST_ERROR(lept_error_type::LEPT_PARSE_EXPECT_VALUE, " ");
}

static void test_parse_invalid_value()
{
    //literal INVALID
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "nul");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "fa");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "t");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "?");

#if 1
    //NUMBER INVALID
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "+0");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "+1");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, ".123"); /* at least one digit before '.' */
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "1.");   /* at least one digit after '.' */
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "1.N");  /* at least one digit after '.' */
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "INF");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "inf");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "NAN");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_VALUE, "nan");
#endif
}

static void test_parse_root_not_singular()
{
    //literal INVALID
    TEST_ERROR(lept_error_type::LEPT_PARSE_ROOT_NOT_SINGULAR, "null x");
#if 1
    /* invalid number */
    TEST_ERROR(lept_error_type::LEPT_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' , 'E' , 'e' or nothing */
    TEST_ERROR(lept_error_type::LEPT_PARSE_ROOT_NOT_SINGULAR, "0x0");
    TEST_ERROR(lept_error_type::LEPT_PARSE_ROOT_NOT_SINGULAR, "0x123");
#endif
}

static void test_parse_number_too_big()
{
#if 1
    TEST_ERROR(lept_error_type::LEPT_PARSE_NUMBER_TOO_BIG, "1e309");
    TEST_ERROR(lept_error_type::LEPT_PARSE_NUMBER_TOO_BIG, "-1e309");
#endif
}

static void test_parse_missing_quotation_mark()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_QUOTATION_MARK, "\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_QUOTATION_MARK, "\"abc");
}

static void test_parse_invalid_string_escape()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\v\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\'\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\0\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_STRING_ESCAPE, "\"\\x12\"");
}

static void test_parse_invalid_string_char()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_STRING_CHAR, "\"\x01\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_STRING_CHAR, "\"\x1F\"");
}

static void test_parse_invalid_unicode_hex()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u01\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u012\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u/000\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\uG000\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0/00\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u0G00\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u00/0\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u00G0\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u000/\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_HEX, "\"\\u000G\"");
}

static void test_parse_invalid_unicode_surrogate()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uDBFF\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\\\\\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\\uDBFF\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_INVALID_UNICODE_SURROGATE, "\"\\uD800\\uE000\"");
}

static void test_parse_miss_comma_or_square_bracket()
{
#if 1
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[1");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[1}");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[1 2");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_SQUARE_BRACKET, "[[]");
#endif
}

static void test_parse_miss_key()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{1:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{true:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{false:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{null:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{[]:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{{}:1,");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_KEY, "{\"a\":1,");
}

static void test_parse_miss_colon()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COLON, "{\"a\"}");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COLON, "{\"a\",\"b\"}");
}

static void test_parse_miss_comma_or_curly_bracket()
{
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1]");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":1 \"b\"");
    TEST_ERROR(lept_error_type::LEPT_PARSE_MISS_COMMA_OR_CURLY_BRACKET, "{\"a\":{}");
}

static void test_parse()
{
    test_parse_null();
    test_parse_false();
    test_parse_true();
    test_parse_number();
    test_parse_string();
    test_parse_array();
    test_parse_object();

    test_parse_expect_value();
    test_parse_invalid_value();
    test_parse_root_not_singular();
    test_parse_number_too_big();
    test_parse_missing_quotation_mark();
    test_parse_invalid_string_escape();
    test_parse_invalid_string_char();
    test_parse_invalid_unicode_hex();
    test_parse_invalid_unicode_surrogate();
    test_parse_miss_comma_or_square_bracket();
    test_parse_miss_key();
    test_parse_miss_colon();
    test_parse_miss_comma_or_curly_bracket();
}

/* ACCESS PARSE */
#define EXPECT_TRUE(actual) EXPECT_EQ_BASE((actual->lept_get_type()) == lept_type::LEPT_TRUE, "true", "false", "%s")
#define EXPECT_FALSE(actual) EXPECT_EQ_BASE((actual->lept_get_type()) == lept_type::LEPT_FALSE, "false", "true", "%s")
#define LEPT_SET_STRING(v, val) ((v).reset(new LeptString(val)))
#define LEPT_SET_NULL(v) ((v).reset(new LeptNull))
#define LEPT_SET_BOOLEAN(v, val) ((val != 0) ? ((v).reset(new LeptTrue)) : ((v).reset(new LeptFalse)))
#define LEPT_SET_NUMBER(v, val) ((v).reset(new LeptNumber(val)))

static void test_access_null()
{
    std::unique_ptr<ILeptJSON> newLept;
    LEPT_SET_STRING(newLept, "a");
    LEPT_SET_NULL(newLept);
    EXPECT_EQ_INT(lept_type::LEPT_NULL, newLept->lept_get_type());
}

static void test_access_boolean()
{
    std::unique_ptr<ILeptJSON> newLept;
    LEPT_SET_STRING(newLept, "a");
    EXPECT_EQ_INT(lept_type::LEPT_STRING, newLept->lept_get_type());
    LEPT_SET_BOOLEAN(newLept, 1);
    EXPECT_TRUE(newLept);
    LEPT_SET_BOOLEAN(newLept, 0);
    EXPECT_FALSE(newLept);
}

static void test_access_number()
{
    std::unique_ptr<ILeptJSON> newLept;
    LEPT_SET_STRING(newLept, "a");
    EXPECT_EQ_INT(lept_type::LEPT_STRING, newLept->lept_get_type());
    LEPT_SET_NUMBER(newLept, 1234.5);
    EXPECT_EQ_DOUBLE(1234.5, newLept->lept_get_element<double>());
}

static void test_access_string()
{
    std::unique_ptr<ILeptJSON> newLept;
    LEPT_SET_STRING(newLept, "a");
    EXPECT_EQ_INT(lept_type::LEPT_STRING, newLept->lept_get_type());
    EXPECT_EQ_STRING("a", newLept->lept_get_element<std::string>());
    LEPT_SET_STRING(newLept, "Hello");
    EXPECT_EQ_STRING("Hello", newLept->lept_get_element<std::string>());
}

static void test_access()
{
    test_access_null();
    test_access_boolean();
    test_access_number();
    test_access_string();
}

/* STRINGIFY TEST*/
#define TEST_STRINGIFY(json)                                                     \
    do                                                                           \
    {                                                                            \
        std::unique_ptr<ILeptJSON> v = MultiManageLeptJSON::lept_parse(json);    \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v->lept_get_error_type()); \
        EXPECT_EQ_STRING(json, v->lept_stringify());                             \
    } while (0)

static void test_stringify_number()
{
    TEST_STRINGIFY("0");
    TEST_STRINGIFY("-0");
    TEST_STRINGIFY("1");
    TEST_STRINGIFY("-1");
    TEST_STRINGIFY("1.5");
    TEST_STRINGIFY("-1.5");
    TEST_STRINGIFY("3.25");
    TEST_STRINGIFY("1e+20");
    TEST_STRINGIFY("1.234e+20");
    TEST_STRINGIFY("1.234e-20");

    TEST_STRINGIFY("1.0000000000000002");      /* the smallest number > 1 */
    TEST_STRINGIFY("4.9406564584124654e-324"); /* minimum denormal */
    TEST_STRINGIFY("-4.9406564584124654e-324");
    TEST_STRINGIFY("2.2250738585072009e-308"); /* Max subnormal double */
    TEST_STRINGIFY("-2.2250738585072009e-308");
    TEST_STRINGIFY("2.2250738585072014e-308"); /* Min normal positive double */
    TEST_STRINGIFY("-2.2250738585072014e-308");
    TEST_STRINGIFY("1.7976931348623157e+308"); /* Max double */
    TEST_STRINGIFY("-1.7976931348623157e+308");
}

static void test_stringify_string()
{
    TEST_STRINGIFY("\"\"");
    TEST_STRINGIFY("\"Hello\"");
    TEST_STRINGIFY("\"Hello\\nWorld\"");
    TEST_STRINGIFY("\"\\\" \\\\ / \\b \\f \\n \\r \\t\"");
    TEST_STRINGIFY("\"Hello\\u0000World\"");
#if 0
    /*多字节unicode解析*/
    TEST_STRINGIFY("\"Hello\\ud834\\udd1eWorld\"");
#endif
}

static void test_stringify_array()
{
    TEST_STRINGIFY("[]");
    TEST_STRINGIFY("[null,false,true,123,\"abc\",[1,2,3]]");
}

static void test_stringify_object()
{
    TEST_STRINGIFY("{}");
    TEST_STRINGIFY("{\"n\":null,\"f\":false,\"t\":true,\"i\":123,\"s\":\"abc\",\"a\":[1,2,3],\"o\":{\"1\":1,\"2\":2,\"3\":3}}");
}

static void test_stringify()
{
    TEST_STRINGIFY("null");
    TEST_STRINGIFY("false");
    TEST_STRINGIFY("true");
    test_stringify_number();
    test_stringify_string();
    test_stringify_array();
    test_stringify_object();
}

/* OTHER */
#define TEST_EQUAL(json1, json2, equality)                                        \
    do                                                                            \
    {                                                                             \
        std::unique_ptr<ILeptJSON> v1 = MultiManageLeptJSON::lept_parse(json1);   \
        std::unique_ptr<ILeptJSON> v2 = MultiManageLeptJSON::lept_parse(json2);   \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v1->lept_get_error_type()); \
        EXPECT_EQ_INT(lept_error_type::LEPT_PARSE_OK, v2->lept_get_error_type()); \
        EXPECT_EQ_INT(equality, (*v1.get() == *v2.get()));                        \
    } while (0)

static void test_equal()
{
    TEST_EQUAL("true", "true", 1);
    TEST_EQUAL("true", "false", 0);
    TEST_EQUAL("false", "false", 1);
    TEST_EQUAL("null", "null", 1);
    TEST_EQUAL("null", "0", 0);
    TEST_EQUAL("123", "123", 1);
    TEST_EQUAL("123", "456", 0);
    TEST_EQUAL("\"abc\"", "\"abc\"", 1);
    TEST_EQUAL("\"abc\"", "\"abcd\"", 0);
    TEST_EQUAL("[]", "[]", 1);
    TEST_EQUAL("[]", "null", 0);
    TEST_EQUAL("[1,2,3]", "[1,2,3]", 1);
    TEST_EQUAL("[1,2,3]", "[1,2,3,4]", 0);
    TEST_EQUAL("[[]]", "[[]]", 1);
    TEST_EQUAL("{}", "{}", 1);
    TEST_EQUAL("{}", "null", 0);
    TEST_EQUAL("{}", "[]", 0);
    TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"a\":1,\"b\":2}", 1);
    TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"b\":2,\"a\":1}", 1);
    TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"a\":1,\"b\":3}", 0);
    TEST_EQUAL("{\"a\":1,\"b\":2}", "{\"a\":1,\"b\":2,\"c\":3}", 0);
    TEST_EQUAL("{\"a\":{\"b\":{\"c\":{}}}}", "{\"a\":{\"b\":{\"c\":{}}}}", 1);
    TEST_EQUAL("{\"a\":{\"b\":{\"c\":{}}}}", "{\"a\":{\"b\":{\"c\":[]}}}", 0);
}

static void test_copy()
{
    /* 如何进行unique_ptr的复制呢 ？*/
    /* 转换成shared_ptr用于共享 */
    std::shared_ptr<ILeptJSON> v1 = MultiManageLeptJSON::lept_parse("{\"t\":true,\"f\":false,\"n\":null,\"d\":1.5,\"a\":[1,2,3]}");   
    std::shared_ptr<ILeptJSON> v2=v1;
    EXPECT_EQ_INT(1,*v1.get()==*v2.get());

}

static void test_move()
{
    std::unique_ptr<ILeptJSON> v1 = MultiManageLeptJSON::lept_parse("{\"t\":true,\"f\":false,\"n\":null,\"d\":1.5,\"a\":[1,2,3]}");   
    std::unique_ptr<ILeptJSON> v2;
    v2=std::move(v1);
    EXPECT_EQ_INT(lept_type::LEPT_OBJECT,v2->lept_get_type());

}

static void test_swap()
{
    std::unique_ptr<ILeptJSON> v1 = MultiManageLeptJSON::lept_parse("\"Hello\"");   
    std::unique_ptr<ILeptJSON> v2 = MultiManageLeptJSON::lept_parse("\"World!\"");   
    v1.swap(v2);
    EXPECT_EQ_STRING("World!", v1->lept_get_element<std::string>());
    EXPECT_EQ_STRING("Hello", v2->lept_get_element<std::string>());
}

int main()
{
    test_parse();
    test_access();
    test_stringify();
    test_equal();
    test_copy();
    test_move();
    test_swap();
    // test_equal();
    printf("%d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    return main_ret;
}
